/**
 * 性能优化相关工具函数
 * 包含防抖、节流等功能
 */

/**
 * 防抖函数
 * 在一定时间内多次触发同一事件，只执行最后一次
 * 
 * @param fn 需要防抖的函数
 * @param delay 延迟时间，单位毫秒，默认300ms
 * @param immediate 是否立即执行，默认false
 * @returns 防抖处理后的函数
 */
export function debounce<T extends (...args: any[]) => any>(
  fn: T,
  delay = 300,
  immediate = false
): (...args: Parameters<T>) => void {
  let timer: ReturnType<typeof setTimeout> | null = null
  
  return function(this: any, ...args: Parameters<T>): void {
    const context = this
    
    if (timer) clearTimeout(timer)
    
    if (immediate) {
      const callNow = !timer
      timer = setTimeout(() => {
        timer = null
      }, delay)
      
      if (callNow) fn.apply(context, args)
    } else {
      timer = setTimeout(() => {
        fn.apply(context, args)
      }, delay)
    }
  }
}

/**
 * 节流函数
 * 在一定时间内多次触发同一事件，按照一定的时间间隔执行
 * 
 * @param fn 需要节流的函数
 * @param interval 时间间隔，单位毫秒，默认300ms
 * @param options 配置选项
 * @param options.leading 是否在开始时立即执行一次，默认true
 * @param options.trailing 是否在结束时再执行一次，默认true
 * @returns 节流处理后的函数
 */
export function throttle<T extends (...args: any[]) => any>(
  fn: T,
  interval = 300,
  options = { leading: true, trailing: true }
): (...args: Parameters<T>) => void {
  let timer: ReturnType<typeof setTimeout> | null = null
  let lastArgs: Parameters<T> | null = null
  let lastTime = 0
  const { leading, trailing } = options
  
  const throttled = function(this: any, ...args: Parameters<T>): void {
    const context = this
    const now = Date.now()
    
    // 如果是第一次调用且不需要立即执行
    if (lastTime === 0 && !leading) {
      lastTime = now
    }
    
    const remaining = interval - (now - lastTime)
    
    if (remaining <= 0) {
      if (timer) {
        clearTimeout(timer)
        timer = null
      }
      
      lastTime = now
      fn.apply(context, args)
      lastArgs = null
    } else if (!timer && trailing) {
      lastArgs = args
      
      timer = setTimeout(() => {
        lastTime = Date.now()
        timer = null
        
        if (lastArgs) {
          fn.apply(context, lastArgs)
          lastArgs = null
        }
      }, remaining)
    }
  }
  
  // 添加取消方法
  throttled.cancel = function(): void {
    if (timer) {
      clearTimeout(timer)
      timer = null
    }
    lastTime = 0
    lastArgs = null
  }
  
  return throttled as (...args: Parameters<T>) => void
}

/**
 * 函数只执行一次
 * 
 * @param fn 需要只执行一次的函数
 * @returns 包装后的函数
 */
export function once<T extends (...args: any[]) => any>(
  fn: T
): (...args: Parameters<T>) => ReturnType<T> | undefined {
  let called = false
  let result: ReturnType<T> | undefined
  
  return function(this: any, ...args: Parameters<T>): ReturnType<T> | undefined {
    if (!called) {
      called = true
      result = fn.apply(this, args)
    }
    return result
  }
}

/**
 * 延迟执行函数
 * 
 * @param fn 需要延迟执行的函数
 * @param delay 延迟时间，单位毫秒
 * @returns Promise，resolve函数执行结果
 */
export function delay<T extends (...args: any[]) => any>(
  fn: T,
  delay: number
): (...args: Parameters<T>) => Promise<ReturnType<T>> {
  return function(this: any, ...args: Parameters<T>): Promise<ReturnType<T>> {
    return new Promise((resolve) => {
      setTimeout(() => {
        resolve(fn.apply(this, args))
      }, delay)
    })
  }
}

/**
 * 重试函数
 * 
 * @param fn 需要重试的函数
 * @param retries 重试次数，默认3次
 * @param interval 重试间隔，单位毫秒，默认1000ms
 * @returns Promise，resolve函数执行结果，reject最后一次错误
 */
export function retry<T>(
  fn: () => Promise<T>,
  retries = 3,
  interval = 1000
): Promise<T> {
  return new Promise<T>((resolve, reject) => {
    const attempt = (attemptsLeft: number): void => {
      fn()
        .then(resolve)
        .catch((error) => {
          if (attemptsLeft <= 1) {
            reject(error)
          } else {
            setTimeout(() => attempt(attemptsLeft - 1), interval)
          }
        })
    }
    
    attempt(retries)
  })
}